"""
简化的WVP集成服务
Simplified WVP Integration Service

提供WVP设备管理的核心功能：
- 设备列表获取
- 播放地址获取  
- 基本的设备数据同步
- 简化的错误处理
"""
import asyncio
import logging
from typing import List, Dict, Optional, Any
from datetime import datetime
from dataclasses import dataclass
from enum import Enum

import httpx
from tenacity import retry, stop_after_attempt, wait_exponential

from config.settings import settings

logger = logging.getLogger(__name__)


class DeviceStatus(str, Enum):
    """设备状态枚举"""
    ONLINE = "online"
    OFFLINE = "offline"
    UNKNOWN = "unknown"


@dataclass
class WVPDevice:
    """WVP设备数据模型"""
    device_id: str
    name: str
    manufacturer: str = ""
    model: str = ""
    ip_address: str = ""
    port: int = 0
    status: DeviceStatus = DeviceStatus.OFFLINE
    longitude: Optional[float] = None
    latitude: Optional[float] = None
    channel_count: int = 0
    last_keepalive: Optional[datetime] = None
    
    @classmethod
    def from_wvp_data(cls, data: Dict[str, Any]) -> 'WVPDevice':
        """从WVP API响应数据创建设备实例"""
        try:
            # 处理时间字段
            last_keepalive = None
            if data.get('keepaliveTime'):
                try:
                    last_keepalive = datetime.fromisoformat(
                        data['keepaliveTime'].replace('Z', '+00:00')
                    )
                except (ValueError, AttributeError):
                    pass
            
            # 确定设备状态
            status = DeviceStatus.ONLINE if data.get('online', 0) == 1 else DeviceStatus.OFFLINE
            
            return cls(
                device_id=data.get('deviceId', ''),
                name=data.get('name', ''),
                manufacturer=data.get('manufacturer', ''),
                model=data.get('model', ''),
                ip_address=data.get('ip', ''),
                port=data.get('port', 0),
                status=status,
                longitude=data.get('longitude'),
                latitude=data.get('latitude'),
                channel_count=data.get('channelCount', 0),
                last_keepalive=last_keepalive
            )
        except Exception as e:
            logger.error(f"解析WVP设备数据失败: {e}")
            # 返回基本设备信息
            return cls(
                device_id=data.get('deviceId', ''),
                name=data.get('name', '未知设备')
            )


class ChannelStatus(str, Enum):
    """通道状态枚举"""
    ONLINE = "online"
    OFFLINE = "offline"
    UNKNOWN = "unknown"


@dataclass
class WVPChannel:
    """WVP通道数据模型"""
    device_id: str
    channel_id: str
    name: str
    status: ChannelStatus = ChannelStatus.OFFLINE
    manufacturer: str = ""
    model: str = ""
    longitude: Optional[float] = None
    latitude: Optional[float] = None
    ptz_type: int = 0  # PTZ类型：0-无，1-球机，2-半球，3-固定枪机，4-遥控枪机
    has_audio: bool = False
    sub_count: int = 0  # 子设备数量
    parent_id: Optional[str] = None  # 父设备ID
    civil_code: str = ""  # 行政区划
    address: str = ""  # 安装地址
    
    @classmethod
    def from_wvp_data(cls, device_id: str, data: Dict[str, Any]) -> 'WVPChannel':
        """从WVP API响应数据创建通道实例"""
        try:
            # 确定通道状态
            status = ChannelStatus.ONLINE if data.get('status', 0) == 1 else ChannelStatus.OFFLINE
            
            return cls(
                device_id=device_id,
                channel_id=data.get('channelId', ''),
                name=data.get('name', ''),
                status=status,
                manufacturer=data.get('manufacturer', ''),
                model=data.get('model', ''),
                longitude=data.get('longitude'),
                latitude=data.get('latitude'),
                ptz_type=data.get('ptzType', 0),
                has_audio=data.get('hasAudio', False),
                sub_count=data.get('subCount', 0),
                parent_id=data.get('parentId'),
                civil_code=data.get('civilCode', ''),
                address=data.get('address', '')
            )
        except Exception as e:
            logger.error(f"解析WVP通道数据失败: {e}")
            # 返回基本通道信息
            return cls(
                device_id=device_id,
                channel_id=data.get('channelId', ''),
                name=data.get('name', '未知通道')
            )


@dataclass
class PlayUrlInfo:
    """播放地址信息"""
    device_id: str
    channel_id: str
    play_url: str
    format_type: str = "flv"
    expires_at: Optional[datetime] = None


class WVPService:
    """简化的WVP集成服务"""
    
    def __init__(self):
        self.base_url = settings.WVP_BASE_URL.rstrip('/')
        self.username = settings.WVP_USERNAME
        self.password = settings.WVP_PASSWORD
        self.api_key = settings.WVP_API_KEY
        self.timeout = 30.0
        
        # 简单的内存缓存
        self._device_cache: Dict[str, WVPDevice] = {}
        self._channel_cache: Dict[str, List[WVPChannel]] = {}  # device_id -> channels
        self._cache_timestamp: Optional[datetime] = None
        self._cache_ttl = 300  # 5分钟缓存
        
    async def _make_request(self, method: str, endpoint: str, **kwargs) -> Optional[Dict[str, Any]]:
        """发起HTTP请求的基础方法"""
        url = f"{self.base_url}{endpoint}"
        
        # 设置认证
        if self.api_key:
            kwargs.setdefault('headers', {})['Authorization'] = f"Bearer {self.api_key}"
        elif self.username and self.password:
            kwargs['auth'] = (self.username, self.password)
        
        try:
            async with httpx.AsyncClient(timeout=self.timeout) as client:
                response = await client.request(method, url, **kwargs)
                response.raise_for_status()
                
                # 尝试解析JSON响应
                try:
                    return response.json()
                except Exception:
                    logger.warning(f"WVP响应不是有效的JSON: {response.text[:200]}")
                    return None
                    
        except httpx.TimeoutException:
            logger.error(f"WVP请求超时: {url}")
            return None
        except httpx.HTTPStatusError as e:
            logger.error(f"WVP请求失败 {e.response.status_code}: {url}")
            return None
        except Exception as e:
            logger.error(f"WVP请求异常: {e}")
            return None
    
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=4, max=10)
    )
    async def get_devices(self, force_refresh: bool = False) -> List[WVPDevice]:
        """获取WVP设备列表"""
        # 检查缓存
        if not force_refresh and self._is_cache_valid():
            logger.debug("使用缓存的设备列表")
            return list(self._device_cache.values())
        
        logger.info("从WVP服务器获取设备列表")
        
        try:
            # 调用WVP API获取设备列表
            response = await self._make_request('GET', '/api/device/query')
            
            if not response or response.get('code') != 0:
                logger.error(f"获取设备列表失败: {response}")
                return []
            
            devices_data = response.get('data', [])
            devices = []
            
            for device_data in devices_data:
                try:
                    device = WVPDevice.from_wvp_data(device_data)
                    devices.append(device)
                    # 更新缓存
                    self._device_cache[device.device_id] = device
                except Exception as e:
                    logger.error(f"解析设备数据失败: {e}")
                    continue
            
            # 更新缓存时间戳
            self._cache_timestamp = datetime.now()
            
            logger.info(f"成功获取 {len(devices)} 个设备")
            return devices
            
        except Exception as e:
            logger.error(f"获取设备列表异常: {e}")
            # 返回缓存数据作为降级方案
            if self._device_cache:
                logger.info("使用缓存数据作为降级方案")
                return list(self._device_cache.values())
            return []
    
    async def get_device(self, device_id: str) -> Optional[WVPDevice]:
        """获取单个设备信息"""
        # 先检查缓存
        if device_id in self._device_cache and self._is_cache_valid():
            return self._device_cache[device_id]
        
        # 从设备列表中查找
        devices = await self.get_devices()
        for device in devices:
            if device.device_id == device_id:
                return device
        
        return None
    
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=4, max=10)
    )
    async def get_channels(self, device_id: str, force_refresh: bool = False) -> List[WVPChannel]:
        """获取设备的通道列表"""
        # 检查缓存
        if not force_refresh and device_id in self._channel_cache and self._is_cache_valid():
            logger.debug(f"使用缓存的通道列表: {device_id}")
            return self._channel_cache[device_id]
        
        logger.info(f"从WVP服务器获取设备通道列表: {device_id}")
        
        try:
            # 调用WVP API获取通道列表
            response = await self._make_request('GET', f'/api/device/query/{device_id}/channel')
            
            if not response or response.get('code') != 0:
                logger.error(f"获取通道列表失败: {response}")
                return []
            
            channels_data = response.get('data', [])
            channels = []
            
            for channel_data in channels_data:
                try:
                    channel = WVPChannel.from_wvp_data(device_id, channel_data)
                    channels.append(channel)
                except Exception as e:
                    logger.error(f"解析通道数据失败: {e}")
                    continue
            
            # 更新缓存
            self._channel_cache[device_id] = channels
            
            logger.info(f"成功获取设备 {device_id} 的 {len(channels)} 个通道")
            return channels
            
        except Exception as e:
            logger.error(f"获取通道列表异常: {e}")
            # 返回缓存数据作为降级方案
            if device_id in self._channel_cache:
                logger.info("使用缓存数据作为降级方案")
                return self._channel_cache[device_id]
            return []
    
    async def get_channel(self, device_id: str, channel_id: str) -> Optional[WVPChannel]:
        """获取单个通道信息"""
        channels = await self.get_channels(device_id)
        for channel in channels:
            if channel.channel_id == channel_id:
                return channel
        return None
    
    async def get_all_channels(self, force_refresh: bool = False) -> Dict[str, List[WVPChannel]]:
        """获取所有设备的通道信息"""
        logger.info("获取所有设备的通道信息")
        
        # 先获取设备列表
        devices = await self.get_devices(force_refresh)
        all_channels = {}
        
        # 并发获取所有设备的通道
        tasks = []
        for device in devices:
            task = self.get_channels(device.device_id, force_refresh)
            tasks.append((device.device_id, task))
        
        # 等待所有任务完成
        for device_id, task in tasks:
            try:
                channels = await task
                all_channels[device_id] = channels
            except Exception as e:
                logger.error(f"获取设备 {device_id} 通道失败: {e}")
                all_channels[device_id] = []
        
        total_channels = sum(len(channels) for channels in all_channels.values())
        logger.info(f"成功获取 {len(all_channels)} 个设备的共 {total_channels} 个通道")
        
        return all_channels
    
    @retry(
        stop=stop_after_attempt(2),
        wait=wait_exponential(multiplier=1, min=2, max=5)
    )
    async def get_play_url(self, device_id: str, channel_id: str = "1", 
                          format_type: str = "flv") -> Optional[PlayUrlInfo]:
        """获取播放地址"""
        logger.info(f"获取播放地址: {device_id}/{channel_id}")
        
        try:
            # 构建播放请求参数
            params = {
                'deviceId': device_id,
                'channelId': channel_id,
                'format': format_type
            }
            
            # 调用WVP播放接口
            response = await self._make_request(
                'POST', 
                f'/api/play/start/{device_id}/{channel_id}',
                params=params
            )
            
            if not response or response.get('code') != 0:
                logger.error(f"获取播放地址失败: {response}")
                return None
            
            play_data = response.get('data', {})
            play_url = play_data.get('url', '')
            
            if not play_url:
                logger.error("播放地址为空")
                return None
            
            return PlayUrlInfo(
                device_id=device_id,
                channel_id=channel_id,
                play_url=play_url,
                format_type=format_type,
                expires_at=datetime.now().replace(hour=23, minute=59, second=59)  # 当天结束
            )
            
        except Exception as e:
            logger.error(f"获取播放地址异常: {e}")
            return None
    
    async def sync_devices(self) -> Dict[str, Any]:
        """同步设备数据"""
        logger.info("开始同步WVP设备数据")
        start_time = datetime.now()
        
        try:
            # 强制刷新设备列表
            devices = await self.get_devices(force_refresh=True)
            
            sync_result = {
                "success": True,
                "start_time": start_time.isoformat(),
                "end_time": datetime.now().isoformat(),
                "total_devices": len(devices),
                "synced_devices": len(devices),
                "message": f"成功同步 {len(devices)} 个设备"
            }
            
            logger.info(f"设备同步完成: {sync_result['message']}")
            return sync_result
            
        except Exception as e:
            error_msg = f"设备同步失败: {e}"
            logger.error(error_msg)
            
            return {
                "success": False,
                "start_time": start_time.isoformat(),
                "end_time": datetime.now().isoformat(),
                "error": error_msg
            }
    
    async def sync_channels(self, device_id: Optional[str] = None) -> Dict[str, Any]:
        """同步通道数据"""
        logger.info(f"开始同步WVP通道数据: {device_id or '所有设备'}")
        start_time = datetime.now()
        
        try:
            if device_id:
                # 同步单个设备的通道
                channels = await self.get_channels(device_id, force_refresh=True)
                total_channels = len(channels)
                synced_devices = 1
            else:
                # 同步所有设备的通道
                all_channels = await self.get_all_channels(force_refresh=True)
                total_channels = sum(len(channels) for channels in all_channels.values())
                synced_devices = len(all_channels)
            
            sync_result = {
                "success": True,
                "start_time": start_time.isoformat(),
                "end_time": datetime.now().isoformat(),
                "synced_devices": synced_devices,
                "total_channels": total_channels,
                "message": f"成功同步 {synced_devices} 个设备的 {total_channels} 个通道"
            }
            
            logger.info(f"通道同步完成: {sync_result['message']}")
            return sync_result
            
        except Exception as e:
            error_msg = f"通道同步失败: {e}"
            logger.error(error_msg)
            
            return {
                "success": False,
                "start_time": start_time.isoformat(),
                "end_time": datetime.now().isoformat(),
                "error": error_msg
            }
    
    def _is_cache_valid(self) -> bool:
        """检查缓存是否有效"""
        if not self._cache_timestamp:
            return False
        
        elapsed = (datetime.now() - self._cache_timestamp).total_seconds()
        return elapsed < self._cache_ttl
    
    def clear_cache(self):
        """清空缓存"""
        self._device_cache.clear()
        self._channel_cache.clear()
        self._cache_timestamp = None
        logger.info("WVP设备和通道缓存已清空")
    
    async def test_connection(self) -> Dict[str, Any]:
        """测试WVP连接"""
        logger.info("测试WVP连接")
        
        try:
            # 尝试获取设备列表来测试连接
            response = await self._make_request('GET', '/api/device/query')
            
            if response and response.get('code') == 0:
                device_count = len(response.get('data', []))
                return {
                    "success": True,
                    "message": f"WVP连接正常，发现 {device_count} 个设备",
                    "device_count": device_count
                }
            else:
                return {
                    "success": False,
                    "message": f"WVP连接失败: {response}"
                }
                
        except Exception as e:
            return {
                "success": False,
                "message": f"WVP连接异常: {e}"
            }


# 全局WVP服务实例
_wvp_service: Optional[WVPService] = None


def get_wvp_service() -> WVPService:
    """获取WVP服务实例"""
    global _wvp_service
    if _wvp_service is None:
        _wvp_service = WVPService()
    return _wvp_service